home *** CD-ROM | disk | FTP | other *** search
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <devices/parallel.h>
- #include <proto/exec.h>
-
- #include <stdio.h>
- #include <stdlib.h>
-
- /*
- * STRUCT:
- * MemNode
- *
- * DESCRIPTION:
- * The MemNode structure is placed at the start of each memory block
- * managed by the safe_ functions.
- *
- * USAGE:
- * It is completely internal to the safe_ suite of functions, no other
- * source need know of it's existance.
- */
- struct MemNode
- {
- struct MemNode *child; /* Next block in list */
-
- char *file; /* File that allocated us */
- ULONG line; /* Line we were allocated on */
-
- ULONG size; /* Size of memory block */
- };
-
-
- /*
- * The head of our internal memory list
- */
- static struct MemNode *far head;
-
- /*
- * When gbl_SafeMem == 0, the SafeMem routines merely call the real versions,
- * without any of the SafeMem checking. This provides an easy way to disable
- * SafeMem without recompiling your entire program.
- */
- ULONG far gbl_SafeMem=1;
-
- /*
- * gbl_SafeMemOutput is the function that is called to print the messages.
- * The default is a _writes() to stdout.
- */
- void (*gbl_SafeMemOutput)() = (void (*)())_writes;
-
- /*
- * FUNCTION:
- * void *safe_AllocMem(Size, MemType, File, Line)
- *
- * DESCRIPTION:
- * Peforms a call to AllocMem() with enhanced error checking. Access
- * to this function should be through the macros in safemem.h -ONLY-.
- * Note that all memory allocated with the safe_ functions must be freed
- * with the safe_ functions.
- *
- * ARGUMENTS:
- * long Size; Size of the block to allocate.
- * long MemType; Type of memory to request.
- * char *File; Calling file (ie __FILE__)
- * int Line; Calling line (ie __LINE__)
- *
- * RETURNS:
- * SUCCESS: A pointer to the new memory block
- * FAILURE: 0
- *
- * WRITTEN:
- * Friday 14-Dec-90 13:02:11 spb
- */
- void *safe_AllocMem(Size, MemType, File, Line)
- ULONG Size;
- ULONG MemType;
- char *File;
- ULONG Line;
- {
- if(gbl_SafeMem)
- {
- struct MemNode *t;
- void *result = 0;
-
- Forbid();
-
- if(head)
- t = head;
- else
- t = 0;
-
- head = (struct MemNode *)AllocMem(Size + sizeof(struct MemNode), MemType);
-
- if(head)
- {
- head->child = t;
- head->file = File;
- head->line = Line;
- head->size = Size;
-
- result = (void *)((long)head + sizeof(struct MemNode));
- }
- else
- head = t;
-
- Permit();
- return(result);
- }
- else
- return((void *)AllocMem(Size, MemType));
- }
-
- /*
- * FUNCTION:
- * void *safe_AllocAbs(Size, Location, File, Line)
- *
- * DESCRIPTION:
- * Peforms a call to AllocAbs() with enhanced error checking. Access
- * to this function should be through the macros in safemem.h -ONLY-.
- * Note that all memory allocated with the safe_ functions must be freed
- * with the safe_ functions.
- *
- * ARGUMENTS:
- * ULONG Size; Size of the block to allocate.
- * void *Location; Where in memory it is
- * char *File; Calling file (ie __FILE__)
- * int Line; Calling line (ie __LINE__)
- *
- * RETURNS:
- * SUCCESS: A pointer to the new memory block
- * FAILURE: 0
- *
- * WRITTEN:
- * Sunday 25-Aug-91 08:46:34 spb
- */
- void *safe_AllocAbs(Size, Location, File, Line)
- ULONG Size;
- void *Location;
- char *File;
- ULONG Line;
- {
- if(gbl_SafeMem)
- {
- struct MemNode *t;
- void *result = 0;
-
- Forbid();
-
- if(head)
- t = head;
- else
- t = 0;
-
- head = (struct MemNode *)AllocAbs(Size + sizeof(struct MemNode),
- (void *)((char *)Location - sizeof(struct MemNode)));
-
- if(head)
- {
- head->child = t;
- head->file = File;
- head->line = Line;
- head->size = Size;
-
- result = (void *)((long)head + sizeof(struct MemNode));
- }
- else
- head = t;
-
- Permit();
- return(result);
- }
- else
- return((void *)AllocAbs(Size, Location));
- }
-
- /*
- * FUNCTION:
- * void safe_FreeMem(Address, Size, File, Line)
- *
- * DESCRIPTION:
- * Peforms a FreeMem() with the enhanced error checking. Must be accessed
- * through the macros in safemem.h. Note that all memory allocated with the
- * safe_ functions must be freed with the safe_ functions.
- *
- * ARGUMENTS:
- * ULONG Address; Location of block to free
- * ULONG Size; Size of block to free
- * char *File; Calling file (__FILE__)
- * ULONG Line; Calling line (__LINE__)
- *
- * WRITTEN:
- * Friday 14-Dec-90 13:02:20 spb
- */
- void safe_FreeMem(Address, Size, File, Line)
- void *Address;
- ULONG Size;
- char *File;
- ULONG Line;
- {
- if(gbl_SafeMem)
- {
- struct MemNode *t1, *t2;
- char buffer[256];
-
- Forbid();
-
- /*
- * Search the list for the node
- */
- t1 = head;
- t2 = 0;
- while(t1)
- {
- if(Address == (void *)((long)t1+sizeof(struct MemNode)))
- {
- /*
- * Found it, but it's the wrong size
- */
- if(Size != t1->size)
- {
- sprintf(buffer, "%s %d: Incorrect free size. (%d instead of %d)\n",
- File, Line, Size, t1->size);
-
- gbl_SafeMemOutput(buffer);
- Permit();
- return;
- }
-
- /*
- * Right size, so remove block from the list
- */
- if(t2)
- t2->child = t1->child;
- else
- head = t1->child;
-
- /*
- * Actually free the memory
- */
- FreeMem(t1, sizeof(struct MemNode)+t1->size);
- Permit();
- return;
- }
-
- t2 = t1;
- t1 = t1->child;
- }
-
- /*
- * We didn't find the block on the list, so it can't be freed.
- * Either a free twice, or never allocated at all.
- */
- sprintf(buffer, "%s %d: Free twice (?) FreeMem($%lx, %d)\n",
- File, Line, Address, Size);
- gbl_SafeMemOutput(buffer);
- Permit();
- return;
- }
- else
- {
- FreeMem(Address, Size);
- return;
- }
- }
-
- /*
- * FUNCTION:
- * ULONG safe_ShowMemList(File, Line)
- *
- * DESCRIPTION:
- * Displays a list of currently unfreed blocks (if there are any) that
- * were allocated with safe_AllocMem. Along with each memory block
- * is the file, function and line it was allocated from.
- * If gbl_Safemem == 0, this function has no effect.
- *
- * ARGUMENTS:
- * char *File; Calling File (__FILE__)
- * ULONG Line; Calling Line (__LINE__)
- *
- * RETURNS:
- * ULONG Number of memoryblocks in the list.
- *
- * WRITTEN:
- * Friday 14-Dec-90 13:02:26 spb
- */
-
- ULONG safe_ShowMemList(File, Line)
- char *File;
- ULONG Line;
- {
- if(gbl_SafeMem)
- {
- char buffer[256];
- ULONG c=0;
- struct MemNode *t;
-
- Forbid(); /* Slightly pointless when printing to the screen, eh? */
- if(head)
- {
- t = head;
- sprintf(buffer, "%s %d: Memory List\n", File, Line);
- gbl_SafeMemOutput(buffer);
- sprintf(buffer, " %-12s %-12s %-16s %-4s\n",
- "Address", "Size", "File", "Line");
- gbl_SafeMemOutput(buffer);
- sprintf(buffer, " %-12s %-12s %-16s %-4s\n",
- "-------", "----", "----", "----");
- gbl_SafeMemOutput(buffer);
-
- while(t)
- {
- sprintf(buffer, " $%-11lx %-12d %-16s %-4d\n",
- t, t->size, t->file, t->line);
- gbl_SafeMemOutput(buffer);
-
- t = t->child;
- c++;
- }
- }
- Permit();
- return(c);
- }
- else
- return(0);
- }
-
- /*
- * FUNCTION:
- * ULONG safe_FreeMemList(File, Line)
- *
- * DESCRIPTION:
- * Frees all the memoryblocks present in the safe_ list. This ensures
- * the environment will get all it's memory back even though the program
- * is faulty, speeding development time.
- * If gbl_SafeMem == 0, this function has no effect.
- *
- * ARGUMENTS:
- * char *File; Calling file (__FILE__)
- * ULONG Line; Calling line (__LINE__)
- *
- * RETURNS:
- * long Number of blocks freed.
- *
- * WRITTEN:
- * Friday 14-Dec-90 13:52:16 spb
- */
-
- ULONG safe_FreeMemList(File, Line)
- char *File;
- ULONG Line;
- {
- if(gbl_SafeMem)
- {
- char buffer[256];
- ULONG c=0;
- struct MemNode *t1, *t2;
-
- Forbid();
- if(head)
- {
- t1 = head;
- sprintf(buffer, "%s %d: Freeing Memory List\n", File, Line);
- gbl_SafeMemOutput(buffer);
-
- while(t1)
- {
- t2 = t1->child;
- FreeMem(t1, t1->size + sizeof(struct MemNode));
- t1 = t2;
- c++;
- }
- }
-
- head = 0;
-
- Permit();
- return(c);
- }
- else
- return(0);
- }
-
- /*
- * FUNCTION:
- * void *safe_malloc(size, file, line)
- *
- * DESCRIPTION:
- * malloc() with with enhanced error checking. Access
- * to this function should be through the macros in safemem.h -ONLY-.
- * Note that all memory allocated with the safe_ functions must be freed
- * with the safe_ functions.
- *
- * malloc(x) is equivalent to AllocMem(x ,MEMF_PUBLIC|MEMF_CLEAR).
- *
- * ARGUMENTS:
- * ULONG size;
- * char *file;
- * ULONG line;
- *
- * RETURNS:
- * SUCCESS: A pointer to the block allocated
- * FAILURE: 0
- *
- * WRITTEN:
- * Saturday 05-Dec-92 16:34:
- */
- void *safe_malloc(size, file, line)
- ULONG size;
- char *file;
- ULONG line;
- {
- struct MemNode *newnode;
- void *result;
-
- if(gbl_SafeMem)
- {
- Forbid();
-
- newnode = (struct MemNode *)AllocMem(size + sizeof(struct MemNode),
- MEMF_PUBLIC | MEMF_CLEAR);
-
- if(newnode)
- {
- newnode->child = head;
- newnode->file = file;
- newnode->line = line;
- newnode->size = size;
- head = newnode;
-
- result = (void *)((long)newnode + sizeof(struct MemNode));
- }
- else
- result = 0;
-
- Permit();
- return(result);
- }
- else
- return(malloc(size));
- }
-
- /*
- * FUNCTION:
- * void safe_free(address, file, line)
- *
- * DESCRIPTION:
- * Safe version of free(). Access should be through the macros.
- *
- * ARGUMENTS:
- * void *address;
- * char *file;
- * ULONG line;
- *
- * WRITTEN:
- * Saturday 05-Dec-92 16:41:
- */
- void safe_free(address, file, line)
- void *address;
- char *file;
- ULONG line;
- {
- struct MemNode *node, *prev;
-
- if(gbl_SafeMem)
- {
- if(address)
- {
- char buffer[256];
-
- Forbid();
-
- prev = 0;
- node = head;
-
- while(node)
- {
- if(address == (void *)((long)node+sizeof(struct MemNode)))
- {
- /*
- * Remove block from the list
- */
- if(prev)
- prev->child = node->child;
- else
- head = node->child;
-
- /*
- * Free the memory
- */
- FreeMem(node, node->size + sizeof(struct MemNode));
- return;
- }
-
- prev = node;
- node = node->child;
- }
-
- sprintf(buffer, "%s %d: Free twice (?) free($%lx)\n",
- file, line, address);
- gbl_SafeMemOutput(buffer);
-
- Permit();
- }
- }
- else
- free(address);
- }
-
- /*
- * FUNCTION:
- * void *safe_realloc(block, newsize, file, line)
- *
- * DESCRIPTION:
- * Safe version of realloc().
- *
- * ARGUMENTS:
- * void *block;
- * ULONG newsize;
- * char *file;
- * ULONG line;
- *
- * RETURNS:
- * SUCCESS: Pointer to new block (pointer may be different to the old block,
- * but the contents will be preserved).
- * FAILURE: 0
- *
- * WRITTEN:
- * Saturday 05-Dec-92 16:42:
- */
- void *safe_realloc(block, newsize, file, line)
- void *block;
- ULONG newsize;
- char *file;
- ULONG line;
- {
- void *newblock;
- struct MemNode *node;
- long oldsize;
-
- if(gbl_SafeMem)
- {
- /*
- * if the oldblock was 0, then this operation is equivalent to a
- * malloc().
- */
- if(!block)
- return(safe_malloc(newsize, file, line));
-
- Forbid();
-
- /*
- * Find the size of the current block
- */
- oldsize = -1;
- node = head;
- while(node)
- {
- if(block == (void *)((long)node+sizeof(struct MemNode)))
- {
- oldsize = node->size;
- break;
- }
-
- node = node->child;
- }
-
- if(oldsize == -1)
- {
- char buffer[256];
- sprintf(buffer, "%s %d: Illegal realloc(%lx, %ld)\n",
- file, line, block, newsize);
- gbl_SafeMemOutput(buffer);
- Permit();
- return(0);
- }
-
- newblock = safe_malloc(newsize, file, line);
- if(newblock)
- {
- memcpy(newblock, block, min(newsize, oldsize));
- safe_free(block, file, line);
- }
-
- Permit();
- return(newblock);
- }
- else
- return(realloc(block, newsize));
- }
-
- /*
- * FUNCTION:
- * void *safe_calloc(elements, elementsize, file, line)
- *
- * DESCRIPTION:
- * Safe version of calloc().
- * Equivalent to malloc(elements*elementsize).
- *
- * ARGUMENTS:
- * ULONG elements, elementsize;
- * char *file;
- * ULONG line;
- *
- * RETURNS:
- * SUCCESS: Pointer to allocated block
- * FAILURE: 0
- *
- * WRITTEN:
- * Saturday 05-Dec-92 16:44:
- */
- void *safe_calloc(elements, elementsize, file, line)
- ULONG elements, elementsize;
- char *file;
- ULONG line;
- {
- return(safe_malloc(elements * elementsize, file, line));
- }
-